#include "defines.h"
#include "serial.h"

#define SCI0 ((volatile struct h8_3069f_sci *)0xffffb0)
#define SCI1 ((volatile struct h8_3069f_sci *)0xffffb8)
#define SCI2 ((volatile struct h8_3069f_sci *)0xffffc0)

struct h8_3069f_sci {
    volatile uint8 smr;
    volatile uint8 brr;
    volatile uint8 scr;
    volatile uint8 tdr;
    volatile uint8 ssr;
    volatile uint8 rdr;
    volatile uint8 scmr;
};

#define SCR_CKE0 (1<<0)
#define SCR_CKE1 (1<<1)
#define SCR_TEIE (1<<2)
#define SCR_MPIE (1<<3)
#define SCR_RE (1<<4)
#define SCR_TE (1<<5)
#define SCR_RIE (1<<6)
#define SCR_TIE (1<<7)

#define SSR_MPBT (1<<0)
#define SSR_MPB (1<<1)
#define SSR_TEND (1<<2)
#define SSR_PER (1<<3)
#define SSR_FER (1<<4)
#define SSR_ORER (1<<5)
#define SSR_RDRF (1<<6)
#define SSR_TDRE (1<<7)

static volatile struct h8_3069f_sci *const sci = SCI1;

#ifdef KZLOAD

#include "timer.h"

#if SERIAL_BITRATE == 9600
#define BRR_VALUE 64
#elif SERIAL_BITRATE == 38400
#define BRR_VALUE 15
#elif SERIAL_BITRATE == 57600
#define BRR_VALUE 10
#else
#error Bad SERIAL_BITRATE
#endif

void serial_init()
{
    sci->scr = 0;
    sci->smr = 0;
    sci->brr = BRR_VALUE;

    delay_us(1000000 / SERIAL_BITRATE + 1);

    sci->scr = SCR_RE | SCR_TE;

    serial_clear();
}

#endif

int serial_is_send_enable()
{
    return sci->ssr & SSR_TDRE;
}

void serial_send_byte(unsigned char c)
{
    while (!serial_is_send_enable())
        ;
    sci->tdr = c;
    sci->ssr &= ~SSR_TDRE;
}

int serial_is_recv_enable()
{
    return sci->ssr & SSR_RDRF;
}

int serial_is_error()
{
    return sci->ssr & (SSR_PER | SSR_FER | SSR_ORER);
}

void serial_clear()
{
    sci->ssr &= ~(SSR_RDRF |
                  SSR_PER |
                  SSR_FER |
                  SSR_ORER);
}

int serial_recv_byte_nocheck()
{
    int c;

    c = sci->rdr;
    sci->ssr &= ~SSR_RDRF;

    return c;
}

int serial_recv_byte()
{
    do {
        if (serial_is_error())
            return -1;
    } while (!serial_is_recv_enable());

    return serial_recv_byte_nocheck();
}

int serial_intr_is_send_enable()
{
    return sci->scr & SCR_TIE;
}

void serial_intr_send_enable()
{
    sci->scr |= SCR_TIE;
}

void serial_intr_send_disable()
{
    sci->scr &= ~SCR_TIE;
}

int serial_intr_is_recv_enable()
{
    return sci->scr & SCR_RIE;
}

void serial_intr_recv_enable()
{
    sci->scr |= SCR_RIE;
}

void serial_intr_recv_disable()
{
    sci->scr &= ~SCR_RIE;
}
